package galaxies.sectors;

import java.awt.Polygon;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import utilities.CoordConvert;
import utilities.MVCMaker;
import view.EViewList;
import view.AbstractView;

import com.jme3.asset.AssetManager;
import com.jme3.math.Vector2f;

import controller.AbstractController;
import controller.IController;
import eventManager.EventManager;
import galaxies.starRegions.StarRegionSpiralArmModel;
import galaxies.starRegions.StarRegionSpiralCoreModel;

public class SpiralSectorBuilder {
	
	private static final Logger logger = Logger.getLogger(SpiralSectorBuilder.class.getName());
	
	public HashMap<Integer, ArrayList<Integer>> remainingLocations;	
	public ArrayList<Integer> offset = new ArrayList<Integer>();
	public ArrayList<ArrayList<Integer>> mainTileList = new ArrayList<ArrayList<Integer>>();
	public ArrayList<ArrayList<Integer>> haloTileList = new ArrayList<ArrayList<Integer>>();
	
	public SpiralSectorBuilder(HashMap<Integer, ArrayList<Integer>> locations, ArrayList<Integer> offset) {
		this.remainingLocations = locations;
		this.offset.clear();
		this.offset.addAll(offset);		
	}
	
	public ArrayList<IController> buildCoreSectors(
			ArrayList<StarRegionSpiralCoreModel> coreRegions, 
			double triangleSide,
			AssetManager assetManager) {
		
		logger.log(Level.INFO, "Build CORE SECTORS");
		
		ArrayList<IController> controllers;
		
		HashMap<String, ArrayList<ArrayList<Integer>>> coreLocations = new HashMap<String, ArrayList<ArrayList<Integer>>>();
		
		double coreSectorRadius = triangleSide*0.4; //define size of the interior core sector as a fraction of the total core size
		
		for (Integer i = 0; i < coreRegions.size(); i++) { //+1 to account for center region, not returned from factory above			
			coreLocations.put("CORE" + i.toString(), new ArrayList<ArrayList<Integer>>());			
		}
		
		int u, v, w;
		ArrayList<Double> cartesians;
		double x,y;
		float dist;
		Vector2f corner1, corner2, corner3;
		ArrayList<Vector2f> verts = new ArrayList<Vector2f>();
		StarRegionSpiralCoreModel region;
		String tempName;
		Integer j;
		ArrayList<Integer> removal = new ArrayList<Integer>();
		
		logger.log(Level.INFO, "Build CORE Polys");
		//Create Java2D polygons using CoreRegion boundaries
		ArrayList<Polygon> polys = new ArrayList<Polygon>();
		for (StarRegionSpiralCoreModel coreRegion: coreRegions) {
			corner1 = coreRegion.getCorners().get(0);
			corner2 = coreRegion.getCorners().get(1);
			corner3 = coreRegion.getCorners().get(2);
			
			Polygon poly = new Polygon();
			poly.addPoint((int) (corner1.x+0.0), (int) (corner1.y+0.0));
			poly.addPoint((int) (corner2.x+0.0), (int) (corner2.y+0.0));
			poly.addPoint((int) (corner3.x+0.0), (int) (corner3.y+0.0));
			
			polys.add(poly);
		}
		logger.log(Level.INFO, "Finished CORE Polys");
		
		logger.log(Level.INFO, "Detect core point locations");
		int k =0;
		for (Map.Entry<Integer, ArrayList<Integer>> entry : remainingLocations.entrySet()) {
			ArrayList<Integer> location = entry.getValue();
			Integer index = entry.getKey();
			
		//for (ArrayList<Integer> location: remainingLocations) {
			//System.out.println(k + " of " + remainingLocations.size());
			k++;
			u = location.get(0); //tile.getU();
			v = location.get(1); //tile.getV();
			w = location.get(2); //tile.getW();
			
			cartesians = CoordConvert.hex2Cart(u, v, w);
			x = cartesians.get(0);
			y = cartesians.get(1);
			//dist = DistanceCalculator.findDistance(x,y, 0.0,0.0);
			
//			if (dist <= coreSectorRadius) {
//				coreLocations.get("CORE0").add(location);
//			}
//			else {
				for (int i = 0; i < polys.size(); i++) {
					j = i;
					if (polys.get(i).contains(x, y)) {
						u+=offset.get(0);
						v+=offset.get(1);
						w+=offset.get(2);
						
						ArrayList<Integer> offsetLocation = new ArrayList<Integer>();
						offsetLocation.add(u);
						offsetLocation.add(v);
						offsetLocation.add(w);
						
						tempName = "CORE" + j.toString();
						coreLocations.get(tempName).add(offsetLocation);
						mainTileList.add(offsetLocation);
						//coreLocations.get(tempName).add(location);
						//mainTileList.add(location);
						removal.add(index);
					}
				}
//			}
		}
		logger.log(Level.INFO, "Finished detect core point locations");
		
		

		logger.log(Level.INFO, "Remove core locations from master array");
		//remove the core tiles from the galaxyTiles array
		for (Integer index: removal) {
			remainingLocations.remove(index);
		}		
		logger.log(Level.INFO, "Finished remove core locations from master array");
		
		controllers = buildGenericSectors(coreLocations, assetManager);		
		return controllers;
	}
	
	public ArrayList<IController> buildArmSectors(
			ArrayList<StarRegionSpiralArmModel> armRegions, 
			AssetManager assetManager) {		
		
		logger.log(Level.INFO, "Building ArmSectors");
		
		ArrayList<IController> controllers;
		
		HashMap<String, ArrayList<ArrayList<Integer>>> armLocations = new HashMap<String, ArrayList<ArrayList<Integer>>>();
		
		for (Integer i = 0; i < armRegions.size(); i++) {			
			armLocations.put("ARM" + i.toString(), new ArrayList<ArrayList<Integer>>());			
		}
		
		ArrayList<Integer> removal = new ArrayList<Integer>();
		double x;
		double y;
		int u, v, w;
		ArrayList<Double> cartesians;
		String tempName;
		
		logger.log(Level.INFO, "Create ARM polys");
		//Create Java2D polygons using CoreRegion boundaries
		ArrayList<Polygon> polys = new ArrayList<Polygon>();
		ArrayList<Vector2f> bounds;
		for (StarRegionSpiralArmModel armRegion: armRegions) {
			bounds = armRegion.getBounds();			
			Polygon poly = new Polygon();
			
			for (Vector2f point: bounds) {
				poly.addPoint((int) (point.x+0.0), (int) (point.y+0.0));				
			}			
			polys.add(poly);
			System.out.println("Poly points= " + poly.npoints);
		}
		logger.log(Level.INFO, "Finished ARM polys");
		
		logger.log(Level.INFO, "Detect ARM locations");
		int k =0;
		for (Map.Entry<Integer, ArrayList<Integer>> entry : remainingLocations.entrySet()) {
			ArrayList<Integer> location = entry.getValue();
			Integer index = entry.getKey();
			if (k%10000==0) {
				System.out.println(k + " of " + remainingLocations.size());				
			}
			k++;
			u = location.get(0); //tile.getU();
			v = location.get(1); //tile.getV();
			w = location.get(2); //tile.getW();
			
			cartesians = CoordConvert.hex2Cart(u, v, w);
			x = cartesians.get(0);
			y = cartesians.get(1);
			//dist = DistanceCalculator.findDistance(x,y, 0.0,0.0);
			
			for (Integer i = 0; i < polys.size(); i++) {
				//j = i;
				if (polys.get(i).contains(x, y)) {
					u+=offset.get(0);
					v+=offset.get(1);
					w+=offset.get(2);
					
					ArrayList<Integer> offsetLocation = new ArrayList<Integer>();
					offsetLocation.add(u);
					offsetLocation.add(v);
					offsetLocation.add(w);
					
					tempName = "ARM" + i.toString();
					armLocations.get(tempName).add(offsetLocation);
					mainTileList.add(offsetLocation);
					//armLocations.get(tempName).add(location);
					//mainTileList.add(location);
					removal.add(index);
				}			
			}
		}
		logger.log(Level.INFO, "Finished ARM locations");
		
		//remove the arm tiles from the galaxyTiles array
		for (Integer index: removal) {
			remainingLocations.remove(index);
		}
		
		for (Map.Entry<Integer, ArrayList<Integer>> entry : remainingLocations.entrySet()) {
			ArrayList<Integer> haloLocation = entry.getValue();
			
			u = haloLocation.get(0)+offset.get(0);
			v = haloLocation.get(1)+offset.get(1);
			w = haloLocation.get(2)+offset.get(2);			
			
			ArrayList<Integer> offsetLocation = new ArrayList<Integer>();
			offsetLocation.add(u);
			offsetLocation.add(v);
			offsetLocation.add(w);
			
			haloTileList.add(offsetLocation);
		}
		
		remainingLocations = null;
		
		System.out.println("MainTileList: " + mainTileList.size());
		
		controllers = buildGenericSectors(armLocations, assetManager);		
		return controllers;	
	}
	
	
	public ArrayList<IController> buildGenericSectors(
			HashMap<String, ArrayList<ArrayList<Integer>>> locations, 
			AssetManager assetManager) {
		
		ArrayList<IController> controllers = new ArrayList<IController>();
		
		ArrayList<ArrayList<Integer>> temp;
		SectorModel sectorModel;
		HashMap<EViewList, AbstractView> sectorView;
		SectorController sectorControl;
		SectorViewBuilder sectorFact = new SectorViewBuilder();
		String name;
		
		//Set up sectors for cores, arms
		for (Map.Entry<String, ArrayList<ArrayList<Integer>>> entry : locations.entrySet()) {
			//build a sector
			temp = entry.getValue();
			name = entry.getKey();
			
			//keys.addAll(temp);
			
			sectorModel = new SectorModel(name, temp);
			sectorView = sectorFact.buildViews(assetManager);
			sectorControl = new SectorController();
			
			MVCMaker.linkElements(sectorModel, sectorView, sectorControl);
			controllers.add(sectorControl);			
		}
		
		return controllers;
		
	}
	
	
	
	
	
	

}
